package city.spring.utils;

import city.spring.modules.system.entity.OrganizationEntity;
import city.spring.modules.system.entity.UserEntity;
import city.spring.modules.system.service.OrganizationService;
import city.spring.modules.system.service.UserService;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;

import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户工具类
 *
 * @author HouKunLin
 * @date 2020/7/10 0010 9:43
 */
@Component
public class UserUtils implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(UserUtils.class);
    private static UserService userService;
    private static OrganizationService organizationService;
    private final boolean isDebug = logger.isDebugEnabled();

    public static Principal getPrincipal() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 获得当前登录对象的用户实体信息
     *
     * @return 返回最新的当前用户信息
     */
    public static UserEntity getUser() {
        return getUser(getPrincipal());
    }

    /**
     * 获得当前登录对象的用户实体信息
     *
     * @param user 安全框架的当前登录对象
     * @return 返回最新的当前用户信息
     */
    public static UserEntity getUser(Principal user) {
        List<GrantedAuthority> authorities = new ArrayList<>();
        boolean loadAuthority = false;
        if (user instanceof OAuth2Authentication) {
            // 使用默认的登录时的权限信息
            authorities.addAll(((OAuth2Authentication) user).getAuthorities());
        } else {
            loadAuthority = true;
            logger.warn("Current Principal is '{}' not 'OAuth2Authentication'", user.getClass());
        }
        UserEntity userEntity = userService.getUserByIdOrAccount(user.getName(), loadAuthority, UserService.UserInfoEnum.ALL);
        if (loadAuthority) {
            // 没有默认的权限信息，使用系统中最新的权限信息
            authorities.addAll(userEntity.getAllAuthorities()
                    .stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList()));
        }
        userEntity.setAuthorities(authorities);
        userEntity.setPassword(null);
        return userEntity;
    }

    /**
     * 获取当前登录用户的组织机构ID
     *
     * @return 组织机构ID
     */
    public static String getOrgId() {
        UserEntity userEntity = userService.getUserByIdOrAccount(getPrincipal().getName());
        if (userEntity == null) {
            return null;
        }
        return userEntity.getOrgId();
    }

    /**
     * 获得当前用户的组织机构列表
     *
     * @return 当前用户组织机构ID，以及子级组织机构ID列表
     */
    public static Set<String> getOrgIds() {
        UserEntity userEntity = userService.getUserByIdOrAccount(getPrincipal().getName());
        if (userEntity == null) {
            return Sets.newHashSet("");
        }
        String orgId = userEntity.getOrgId();
        Set<String> ids = Sets.newHashSet();
        // 没有组织机构的用户
        if (orgId == null || "".equals(orgId)) {
            Set<String> orgIdSet = organizationService.lambdaQuery()
                    .isNull(OrganizationEntity::getPid).or().eq(OrganizationEntity::getPid, "")
                    .list().stream().map(OrganizationEntity::getId).collect(Collectors.toSet());
            ids.addAll(orgIdSet);
            // 加一个默认的空的组织机构信息
            ids.add("");
        } else {
            OrganizationEntity byId = organizationService.getById(userEntity.getOrgId());
            if (byId == null) {
                return Sets.newHashSet(userEntity.getOrgId());
            }
            ids.add(byId.getId());
        }

        ids.addAll(organizationService.getChildrenIds(ids));

        return ids;
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        userService = applicationContext.getBean(UserService.class);
        organizationService = applicationContext.getBean(OrganizationService.class);
    }
}
